package com.zhouyu.mini.spring;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 周瑜
 * spring自带的
 */

public class AopBeanPostProcessor implements BeanPostProcessor {

    private List<ZhouyuAdvisor> advisors = new ArrayList<>();

    public AopBeanPostProcessor(ZhouyuApplicationContext applicationContext) {
        for (Map.Entry<String, BeanDefinition> entry : applicationContext.getBeanDefinitionMap().entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            Class<?> beanClass = beanDefinition.getBeanClass();
            if (beanClass.isAnnotationPresent(Aspect.class)) {
                for (Method method : beanClass.getDeclaredMethods()) {
                    if (method.isAnnotationPresent(Before.class)) {
                        String pointcut = method.getAnnotation(Before.class).value();
                        ZhouyuAdvisor advisor = new ZhouyuAdvisor(pointcut, method, applicationContext.getBean(beanName));
                        advisors.add(advisor);
                    }
                }
            }
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        for (ZhouyuAdvisor advisor : advisors) {
            String pointcut = advisor.getPointcut();
            Method advice = advisor.getAdvice();

            if (pointcut.contains(bean.getClass().getSimpleName())) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(bean.getClass());
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                        // 切面逻辑
                        advice.invoke(advisor.getAspect(), args);

                        // 执行原本逻辑
                        return method.invoke(bean, args);
                    }
                });
                return enhancer.create();
            }
        }
        return bean;
    }
}
